#ifndef STEINER_MERGE_POINT_H
#define STEINER_MERGE_POINT_H

#include <memory>
#include <list>
#include <map>
#include "Point2D.h"
#include "Arithmetic.h"

namespace STEINER {

template <typename T>
class MergePoint : public Point2D<T>
{
public:
    using SPtr = std::shared_ptr<MergePoint<T> >;
    using WPtr = std::shared_ptr<MergePoint<T> >;


    MergePoint() : Point2D<T>() {}
    MergePoint(const T _x, const T _y) : Point2D<T>(_x, _y) {}
    virtual ~MergePoint() {}

    bool operator==(const MergePoint& that) {
        return static_cast<Point2D<T> >(*this) == static_cast<Point2D<T> >(that);
    }

    std::list<MergePoint::WPtr> GetConns() const {
        return conns;
    }

    void CalAngelWithY() {
        angle = VecAng(MergePoint::x, MergePoint::y, 0, 0, 0, 1);
    }

    double GetAngle() const {
        return angle;
    }

    bool AddDominatedPoint(const MergePoint::SPtr& point) {
        for (const auto p : dominatedPoints) {
            if (*p == *point) {
                return false;
            }
        }
        dominatedPoints.emplace_back(point);
        return true;
    }

    T GetLengthOfDominatedPoints() const {
        std::list<std::pair<T, T> > coords;
        for (const auto p : dominatedPoints) {
            auto sp = p.lock();
            if (nullptr != sp) {
                coords.emplace_back(std::make_pair(p->GetX(), p->GetY()));
            }
        }
        return GetManhattan(Point2D<T>::x, Point2D<T>::y, coords);
    }

    std::list<MergePoint::WPtr> GetDominatedPoints() const {
        return dominatedPoints;
    }

    void ClearDominatedPoints() {
        dominatedPoints.clear();
    }

    bool AddConnPoint(const MergePoint::SPtr& point) {
        for (const auto p : conns) {
            auto sp = p.lock();
            if (nullptr != sp && *sp == *point) {
                return false;
            }
        }
        conns.emplace_back(point);
        return true;
    }

protected:
    double angle;
    std::list<MergePoint::WPtr> conns;
    std::list<MergePoint::WPtr> dominatedPoints;

};

template <typename T>
struct CompareMergeSPtrAngle
{
    using MergePointSPtr = std::shared_ptr<MergePoint<T> >;
    bool operator()(const MergePointSPtr& left, const MergePointSPtr& right) {
        return left->GetAngle() <= right->GetAngle();
    }
};

}

#endif
